using System;
using System.Text;

namespace SAP.BusinessOne.Mackinac.Generator.Razor
{
    public class Template : ITemplate
    {
        public Template()
        {
            Buffer = new StringBuilder();
        }

        public StringBuilder Buffer { get; private set; }
        public string Result { get { return Buffer.ToString(); } }
        public virtual void Execute() { }

        public void Write(object @object)
        {
            if (@object == null)
                return;

            Buffer.Append(@object);
        }
        public void WriteLiteral(string @string)
        {
            if (@string == null)
                return;

            Buffer.Append(@string);
        }

        /// <summary>
        /// This method is used to write out attribute values using
        /// some funky nested tuple storage.
        /// 
        /// Handles situations like href="@Model.Entry.Id"
        /// 
        /// This call comes in from the Razor runtime parser
        /// </summary>
        /// <param name="attr"></param>
        /// <param name="tokens"></param>
        public virtual void WriteAttribute(string attr,
                                           Tuple<string, int> token1,
                                           Tuple<string, int> token2,
                                           Tuple<Tuple<string, int>, Tuple<object, int>, bool> token3)
        {
            object value;
            if (token3 != null)
                value = token3.Item2.Item1;
            else
                value = string.Empty;

            var output = token1.Item1 + value.ToString() + token2.Item1;

            Buffer.Append(output);
        }

        public virtual void WriteAttribute(string name, Tuple<string, int> startTag, Tuple<string, int> endTag, params object[] values)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(startTag.Item1);

            Type[] types = new[] { typeof(object), typeof(string), typeof(decimal), typeof(bool), typeof(char), typeof(byte), typeof(sbyte), typeof(short), typeof(int), typeof(long), typeof(ushort), typeof(uint), typeof(ulong), typeof(float), typeof(double) };

            // All values must be of type:
            // Tuple<Tuple<string, int>, Tuple<______, int>, bool>
            //       ----- TupleA -----  ----- TupleB -----  bool

            Type genTuple = typeof(Tuple<,>);
            Type genTriple = typeof(Tuple<,,>);

            Type tupleA = genTuple.MakeGenericType(typeof(string), typeof(int));

            foreach (var value in values)
            {
                // Find the type of this value
                foreach (Type type in types)
                {
                    Type tupleB = genTuple.MakeGenericType(type, typeof(int));
                    Type nonGen = genTriple.MakeGenericType(tupleA, tupleB, typeof(bool));

                    // Check if value is this type
                    if (!nonGen.IsInstanceOfType(value))
                        continue;

                    // Found
                    // Convert it to this
                    dynamic typedObject = Convert.ChangeType(value, nonGen);

                    if (typedObject == null)
                        continue;

                    sb.Append(WriteAttribute(typedObject));
                    break;
                }
            }

            sb.Append(endTag.Item1);

            Buffer.Append(sb);
        }
        private static string WriteAttribute<P>(Tuple<Tuple<string, int>, Tuple<P, int>, bool> value)
        {
            if (value == null)
                return string.Empty;

            StringBuilder sb = new StringBuilder();

            sb.Append(value.Item1.Item1);
            sb.Append(value.Item2.Item1);

            return sb.ToString();
        }

        public dynamic ViewBag { get; set; }
    }
}